﻿using System;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using System.Text.RegularExpressions;
using XXX.Common;

namespace XXX.api.Log
{
    public class RequestResponseLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private RequestResponseLog _logInfo;

        public RequestResponseLoggingMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            _logInfo = new RequestResponseLog();

            HttpRequest request = context.Request;
            _logInfo.Url = request.Path.ToString();
            _logInfo.Headers = request.Headers.ToDictionary(k => k.Key, v => string.Join(";", v.Value.ToList()));
            _logInfo.Method = request.Method;
            _logInfo.ExcuteStartTime = DateTime.Now;

            //获取request.Body内容
            if (request.Method.ToLower().Equals("post"))
            {
                //request.EnableBuffering();
                //request.EnableRewind(); //启用倒带功能，就可以让 Request.Body 可以再次读取
                //HttpRequestRewindExtensions.EnableBuffering(request);
                //Stream stream = request.Body;
                //byte[] buffer = new byte[request.ContentLength.Value];
                //stream.Read(buffer, 0, buffer.Length);
                //_logInfo.RequestBody = Encoding.UTF8.GetString(buffer);

                //request.Body.Position = 0;

                // 启用倒带功能，就可以让 Request.Body 可以再次读取
                request.EnableBuffering();

                //java 调用乱码，测试工具postman正常

                Stream stream = request.Body;
                
                   
                 
           //压缩测试乱码，无用
           //Stream stream = new System.IO.Compression.GZipStream(request.Body, System.IO.Compression.CompressionMode.Decompress);


                    //获取到body值
                    string bodyAsText = await new StreamReader(request.Body).ReadToEndAsync();
                //处理中文乱码 20221209，一径测试
                //string bodyAsTextNew;
                //byte[] buffer = Encoding.GetEncoding("GB2312").GetBytes(bodyAsText);
                //bodyAsText = Encoding.UTF8.GetString(buffer);

                //修改body值
                //bodyAsText = Regex.Replace(bodyAsText, "(\":\")([0-9]{16,19})(\",)", "\":$2,");
                MemoryStream ms1 = null;
                StreamWriter writer = null;
                //放到流中回填回去
                ms1 = new MemoryStream();
                writer = new StreamWriter(ms1);
                writer.Write(bodyAsText);
                writer.Flush();
                _logInfo.RequestBody = bodyAsText;
                request.Body = ms1;
                request.Body.Position = 0;

            }
            else if (request.Method.Equals("get") || request.Method.Equals("GET"))
            {
                _logInfo.RequestBody = request.QueryString.Value;
            }

            //获取Response.Body内容
            var originalBodyStream = context.Response.Body;

            using (var responseBody = new MemoryStream())
            {
                context.Response.Body = responseBody;

                await _next(context);

                _logInfo.ResponseBody = await FormatResponse(context.Response);
               
                _logInfo.ExcuteEndTime = DateTime.Now;
                //去掉swagger的显示
                if (!_logInfo.ToString().Contains("swagger"))
                { 
                LoggerHelper loggerHelper = new LoggerHelper();
                loggerHelper.Debug("API",$"VisitLog:{_logInfo.ToString()}");
                }
                await responseBody.CopyToAsync(originalBodyStream);
            }
        }

        private async Task<string> FormatResponse(HttpResponse response)
        {
            response.Body.Seek(0, SeekOrigin.Begin);
            var text = await new StreamReader(response.Body).ReadToEndAsync();
            response.Body.Seek(0, SeekOrigin.Begin);

            return text;
        }
    }

    public static class RequestResponseLoggingMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestResponseLoggingMiddleware>();
        }
    }
}